﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SharpSoft.WPF.Controls
{
    /// <summary>
    /// 2D视图浏览控件 
    /// </summary>
    public class Thumb2DControl : Grid
    {
        public Thumb2DControl()
        {
            this.ClipToBounds = true;

            this.Loaded += Thumb2DControl_Loaded;

        }

        private void Thumb2DControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                this.ResetView();
            }
        }


        public delegate object Thumb2DControlGenerateView(int viewIndex);
        static Thumb2DControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Thumb2DControl), new FrameworkPropertyMetadata(typeof(Thumb2DControl)));
        }



        /// <summary>
        /// 可见的视图数量(必须为奇数，如果是偶数则会自动+1)
        /// </summary>
        public int MaxViewCount
        {
            get { return (int)GetValue(MaxViewCountProperty); }
            set { SetValue(MaxViewCountProperty, value); }
        }
        List<int> indexs;
        /// <summary>
        /// 替补内容
        /// </summary>
        private ContentControl sub;

        public static readonly DependencyProperty MaxViewCountProperty =
            DependencyProperty.Register("MaxViewCount", typeof(int), typeof(Thumb2DControl), new PropertyMetadata(3, new PropertyChangedCallback(
                (s, e) =>
                {
                    Thumb2DControl thumb = (Thumb2DControl)s;
                    if (thumb.MaxViewCount % 2 == 0)
                    {
                        thumb.MaxViewCount++;
                        return;
                    }
                    if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(thumb))
                    {
                        thumb.ResetView();
                    }
                }
                )));


        /// <summary>
        /// 当前视图索引
        /// </summary>
        public int CurrentViewIndex
        {
            get { return (int)GetValue(CurrentViewIndexProperty); }
            private set { SetValue(CurrentViewIndexProperty, value); }
        }

        public static readonly DependencyProperty CurrentViewIndexProperty =
            DependencyProperty.Register("CurrentViewIndex", typeof(int), typeof(Thumb2DControl), new PropertyMetadata(0));


        /// <summary>
        /// 指定一个缩放比例来定义两侧内容的偏移距离
        /// </summary>
        public double PositionScale
        {
            get { return (double)GetValue(PositionScaleProperty); }
            set { SetValue(PositionScaleProperty, value); }
        }

        public static readonly DependencyProperty PositionScaleProperty =
            DependencyProperty.Register("PositionScale", typeof(double), typeof(Thumb2DControl), new PropertyMetadata(0.3d));



        /// <summary>
        /// 为指定的数据提供视图
        /// </summary>
        public event Thumb2DControlGenerateView GenerateView;

        /// <summary>
        /// 前翻
        /// </summary>
        public void Previous()
        {//预加载前一个
            var i = indexs[0] - 1;
            var content = this.GenerateView(i);
            this.sub.Content = content;
            this.aniRight();
        }
        /// <summary>
        /// 后翻
        /// </summary>
        public void Next()
        {//预加载后一个
            var i = indexs[indexs.Count - 1] + 1;
            var content = this.GenerateView(i);
            this.sub.Content = content;
            this.aniLeft();
        }
        /// <summary>
        /// 重置视图
        /// </summary>
        public void ResetView()
        {
            if (this.GenerateView == null)
            {
                throw new Exception("未实现视图提供事件。请实现“GenerateView”以提供指定索引的视图。");
            }
            this.Children.Clear();
            for (int i = 0; i < this.MaxViewCount; i++)
            {
                var cc = new ContentControl() { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
                var tg1 = new TransformGroup();
                tg1.Children.Add(new TranslateTransform());
                tg1.Children.Add(new ScaleTransform());
                tg1.Children.Add(new RotateTransform());
                tg1.Children.Add(new SkewTransform());
                cc.RenderTransform = tg1;
                cc.RenderTransformOrigin = new Point(0.5d, 0.5d);
                this.Children.Add(cc);
                cc.Height = this.ActualHeight;
                cc.Width = cc.Height / 0.618d;
            }
            this.sub = new ContentControl() { Visibility = Visibility.Collapsed, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
            this.sub.RenderTransformOrigin = new Point(0.5d, 0.5d);
            var tg = new TransformGroup();
            tg.Children.Add(new TranslateTransform());
            tg.Children.Add(new ScaleTransform());
            tg.Children.Add(new RotateTransform());
            tg.Children.Add(new SkewTransform());
            this.sub.RenderTransform = tg;
            this.Children.Add(this.sub);
            //this.MeasureCore(new Size(this.ActualWidth, this.ActualHeight));
            //this.ArrangeCore(new Rect(new Point(), new Size(this.ActualWidth, this.ActualHeight)));
            this.UpdateLayout();
            var half = this.MaxViewCount / 2;
            indexs = new List<int>(this.MaxViewCount - 1);
            for (int i = half; i > 0; i--)
            {
                indexs.Add(this.CurrentViewIndex - i);
            }
            indexs.Add(this.CurrentViewIndex);
            for (int i = 1; i <= half; i++)
            {
                indexs.Add(this.CurrentViewIndex + i);

            }
            for (int i = 0; i < indexs.Count; i++)
            {
                var content = this.GenerateView(indexs[i]);
                var cc = this.Children[i] as ContentControl;
                cc.Content = content;
            }
            this.ResetTransform();

        }

        private void ResetTransform()
        {
            var index = 0;
            var center = this.Children[indexs.Count / 2] as ContentControl;
            int minzindex = 0;
            foreach (var item in indexs)
            {
                var offset = item - this.CurrentViewIndex;
                var zindex = -Math.Abs(offset);
                minzindex = Math.Min(zindex, minzindex);
                Panel.SetZIndex(this.Children[index], zindex);

                var scale = Math.Pow(0.8, Math.Abs(offset));

                var tg = this.Children[index].RenderTransform as TransformGroup;
                var scaleTransform = tg.Children[1] as ScaleTransform;
                scaleTransform.ScaleX = scale;
                scaleTransform.ScaleY = scale;
                var translateTransform = tg.Children[0] as TranslateTransform;
                translateTransform.X = offset * center.ActualWidth * this.PositionScale;
                index++;
            }
            Panel.SetZIndex(this.sub, minzindex);
        }

        /// <summary>
        /// 往左动画
        /// </summary>
        private void aniLeft()
        {
            this.sub.Visibility = Visibility.Visible;//显示替补内容
            this.sub.RenderTransform = this.Children[this.Children.Count - 2].RenderTransform.Clone();//替补内容占据最右面位置
            double? lastscale = null;
            double? lastx = null;
            Duration duration = new Duration(TimeSpan.FromMilliseconds(500));
            Storyboard storyboard = new Storyboard();
            storyboard.Completed += (s, e) =>
            {
                this.sub.Visibility = Visibility.Collapsed;
                this.CurrentViewIndex++;
                this.ResetView();
            };
            storyboard.FillBehavior = FillBehavior.Stop;


            for (int i = 0; i < this.Children.Count - 1; i++)//附加的内容控件单独处理
            {
                var cc = this.Children[i] as ContentControl;
                //  cc.Opacity = 0.5;
                var tg = cc.RenderTransform as TransformGroup;
                var translateTransform = tg.Children[0] as TranslateTransform;
                var scaleTransform = tg.Children[1] as ScaleTransform;
                var scale = scaleTransform.ScaleX;
                var x = translateTransform.X;
                if (!lastx.HasValue)
                {//往左时首个内容渐隐消失
                    DoubleAnimation oani = new DoubleAnimation(0, duration);
                    Storyboard.SetTarget(oani, cc);
                    Storyboard.SetTargetProperty(oani, new PropertyPath("Opacity"));
                    storyboard.Children.Add(oani);
                }
                else
                {//创建往前的动画
                    DoubleAnimation xani = new DoubleAnimation(lastx.Value, duration);
                    Storyboard.SetTarget(xani, cc);
                    Storyboard.SetTargetProperty(xani, new PropertyPath("(ContentControl.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"));
                    DoubleAnimation sxani = new DoubleAnimation(lastscale.Value, duration);
                    Storyboard.SetTarget(sxani, cc);
                    Storyboard.SetTargetProperty(sxani, new PropertyPath("(ContentControl.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleX)"));
                    DoubleAnimation syani = new DoubleAnimation(lastscale.Value, duration);
                    Storyboard.SetTarget(syani, cc);
                    Storyboard.SetTargetProperty(syani, new PropertyPath("(ContentControl.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleY)"));
                    storyboard.Children.Add(xani);
                    storyboard.Children.Add(sxani);
                    storyboard.Children.Add(syani);


                    DoubleAnimation oani1 = new DoubleAnimation(1, 0.5, new Duration(TimeSpan.FromMilliseconds(250)));
                    Storyboard.SetTarget(oani1, cc);
                    Storyboard.SetTargetProperty(oani1, new PropertyPath("Opacity"));
                    storyboard.Children.Add(oani1);
                    //DoubleAnimation oani2 = new DoubleAnimation(0.5, 1, new Duration(TimeSpan.FromMilliseconds(600))) { BeginTime = TimeSpan.FromMilliseconds(600) };
                    //Storyboard.SetTarget(oani2, cc);
                    //Storyboard.SetTargetProperty(oani2, new PropertyPath("Opacity"));
                    //storyboard.Children.Add(oani2);
                }
                lastx = x;
                lastscale = scale;
            }

            DoubleAnimation subani = new DoubleAnimation(0, 0.5, duration);
            Storyboard.SetTarget(subani, this.sub);
            Storyboard.SetTargetProperty(subani, new PropertyPath("Opacity"));
            storyboard.Children.Add(subani);
            storyboard.Begin();
        }


        /// <summary>
        /// 往右动画
        /// </summary>
        private void aniRight()
        {
            this.sub.Visibility = Visibility.Visible;//显示替补内容
            this.sub.RenderTransform = this.Children[0].RenderTransform.Clone();//替补内容占据最左面位置
            double? lastscale = null;
            double? lastx = null;
            Duration duration = new Duration(TimeSpan.FromMilliseconds(500));
            Storyboard storyboard = new Storyboard();
            storyboard.Completed += (s, e) =>
            {
                this.sub.Visibility = Visibility.Collapsed;
                this.CurrentViewIndex--;
                this.ResetView();
            };
            storyboard.FillBehavior = FillBehavior.Stop;


            for (int i = this.Children.Count - 2; i >= 0; i--)//附加的内容控件单独处理
            {
                var cc = this.Children[i] as ContentControl;
                //  cc.Opacity = 0.5;
                var tg = cc.RenderTransform as TransformGroup;
                var translateTransform = tg.Children[0] as TranslateTransform;
                var scaleTransform = tg.Children[1] as ScaleTransform;
                var scale = scaleTransform.ScaleX;
                var x = translateTransform.X;
                if (!lastx.HasValue)
                {//往右时末尾内容渐隐消失
                    DoubleAnimation oani = new DoubleAnimation(0, duration);
                    Storyboard.SetTarget(oani, cc);
                    Storyboard.SetTargetProperty(oani, new PropertyPath("Opacity"));
                    storyboard.Children.Add(oani);
                }
                else
                {//创建往前的动画
                    DoubleAnimation xani = new DoubleAnimation(lastx.Value, duration);
                    Storyboard.SetTarget(xani, cc);
                    Storyboard.SetTargetProperty(xani, new PropertyPath("(ContentControl.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"));
                    DoubleAnimation sxani = new DoubleAnimation(lastscale.Value, duration);
                    Storyboard.SetTarget(sxani, cc);
                    Storyboard.SetTargetProperty(sxani, new PropertyPath("(ContentControl.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleX)"));
                    DoubleAnimation syani = new DoubleAnimation(lastscale.Value, duration);
                    Storyboard.SetTarget(syani, cc);
                    Storyboard.SetTargetProperty(syani, new PropertyPath("(ContentControl.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleY)"));
                    storyboard.Children.Add(xani);
                    storyboard.Children.Add(sxani);
                    storyboard.Children.Add(syani);


                    DoubleAnimation oani1 = new DoubleAnimation(1, 0.5, new Duration(TimeSpan.FromMilliseconds(250)));
                    Storyboard.SetTarget(oani1, cc);
                    Storyboard.SetTargetProperty(oani1, new PropertyPath("Opacity"));
                    storyboard.Children.Add(oani1);
                    //DoubleAnimation oani2 = new DoubleAnimation(0.5, 1, new Duration(TimeSpan.FromMilliseconds(600))) { BeginTime = TimeSpan.FromMilliseconds(600) };
                    //Storyboard.SetTarget(oani2, cc);
                    //Storyboard.SetTargetProperty(oani2, new PropertyPath("Opacity"));
                    //storyboard.Children.Add(oani2);
                }
                lastx = x;
                lastscale = scale;
            }

            DoubleAnimation subani = new DoubleAnimation(0, 0.5, duration);
            Storyboard.SetTarget(subani, this.sub);
            Storyboard.SetTargetProperty(subani, new PropertyPath("Opacity"));
            storyboard.Children.Add(subani);
            storyboard.Begin();
        }

        private void Storyboard_Completed(object sender, EventArgs e)
        {
        }
    }
}
